package retrieval;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;

import javax.swing.JOptionPane;

import org.dom4j.Document;

import utils.ObjectPersistence;

public class CreateDAGBKI implements Serializable
{
    public static Hashtable<String, QueryInfo>                            queryList       = new Hashtable<String, QueryInfo>();
    public static Hashtable<String, HashSet<String>>                      keyword2query   = new Hashtable<String, HashSet<String>>();
    public static Hashtable<String, HashSet<String>>                      parents2query   = new Hashtable<String, HashSet<String>>();
    public static Hashtable<String, HashSet<String>>                      query2parents   = new Hashtable<String, HashSet<String>>();
    public static Hashtable<String, HashSet<String>>                      uselessNodeList = new Hashtable<String, HashSet<String>>();
    public static HashSet<String>                                         keywordSet      = new HashSet<String>();
    public static Hashtable<String, Hashtable<String, HashSet<Document>>> queryResult     = new Hashtable<String, Hashtable<String, HashSet<Document>>>();
    String[]                                                              keywords;
    String                                                                query;
    HashSet<String>                                                       QInList         = new HashSet<String>();
    HashSet<String>                                                       InQList         = new HashSet<String>();

    public void insertQueryToGraph(String queryInfo)
    {
        this.query = queryInfo;
        this.keywords = this.query.split(" ");

        QInList = new HashSet<String>();
        InQList = new HashSet<String>();
        try
        {
            if (queryList.containsKey(query))
            {
                JOptionPane.showMessageDialog(null, "Query:'" + query
                        + "'has been registered! ");
            }
            else
            {
                QueryInfo currQueryInfo = new QueryInfo();
                currQueryInfo.query = query;
                currQueryInfo.inDegree = 0;
                for (int i = 0; i < keywords.length; i++)
                    currQueryInfo.keywords.add(new String(keywords[i]));
                queryList.put(query, currQueryInfo);
                query2parents.put(query, new HashSet<String>());
                parents2query.put(query, new HashSet<String>());
                uselessNodeList.put(query, new HashSet<String>());

                for (int j = 0; j < keywords.length; j++)
                {
                    if (!keywordSet.contains(new String(keywords[j])))
                    {
                        keywordSet.add(new String(keywords[j]));
                        keyword2query.put(keywords[j], new HashSet<String>());
                        keyword2query.get(keywords[j]).add(new String(query));
                        queryList.get(query).inDegree++;
                    }
                    else
                    {
                        String[] keyword2querys = this.toArray(keyword2query
                                .get(keywords[j]));
                        for (int k = 0; k < keyword2querys.length; k++)
                        {
                            if (!(QInList
                                    .contains(new String(keyword2querys[k])) || InQList
                                    .contains(new String(keyword2querys[k]))))
                            {
                                int tmp = judgeInclusion(keyword2querys[k],
                                        query);
                                if (tmp > 0)
                                    InQList.add(new String(keyword2querys[k]));
                                else if (tmp < 0)
                                    QInList.add(new String(keyword2querys[k]));
                                else
                                {
                                    keyword2query.get(keywords[j]).add(
                                            new String(query));
                                    queryList.get(query).inDegree++;
                                }
                            }
                        }
                    }
                }

                if (!QInList.isEmpty())
                {
                    int tmp = 0;
                    String[] queryKeywords = this
                            .toArray(queryList.get(query).keywords);
                    for (int i = 0; i < queryKeywords.length; i++)
                    {
                        HashSet<String> set = keyword2query
                                .get(queryKeywords[i]);
                        if (set.containsAll(QInList))
                        {
                            keyword2query.get(queryKeywords[i]).removeAll(
                                    QInList);
                            keyword2query.get(queryKeywords[i]).add(
                                    new String(query));
                            queryList.get(query).inDegree++;
                            tmp++;
                        }
                    }
                    String[] QInLists = this.toArray(QInList);
                    for (int j = 0; j < QInLists.length; j++)
                    {
                        query2parents.get(query).add(new String(QInLists[j]));
                        parents2query.get(QInLists[j]).add(new String(query));
                        queryList.get(QInLists[j]).inDegree = queryList
                                .get(QInLists[j]).inDegree
                                - tmp + 1;
                    }
                }
                if (!InQList.isEmpty())
                {
                    if (InQList.size() > 1)
                    {
                        while (minimizeInQList())
                        {}
                    }
                    String[] finalInQList = this.toArray(InQList);
                    for (int k = 0; k < finalInQList.length; k++)
                    {
                        parents2query.get(query).add(
                                new String(finalInQList[k]));
                        query2parents.get(finalInQList[k]).add(
                                new String(query));
                        queryList.get(query).inDegree++;
                    }
                }
            }
            this.save();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public void save() throws IOException
    {
        ObjectPersistence<Hashtable<String, QueryInfo>> op1 = new ObjectPersistence<Hashtable<String, QueryInfo>>();
        ObjectPersistence<Hashtable<String, HashSet<String>>> op2 = new ObjectPersistence<Hashtable<String, HashSet<String>>>();
        ObjectPersistence<HashSet<String>> op3 = new ObjectPersistence<HashSet<String>>();
        op1.save(queryList, new File("queryList.dag"));
        op2.save(keyword2query, new File("keyword2query.dag"));
        op2.save(query2parents, new File("query2parents.dag"));
        op2.save(parents2query, new File("parents2query.dag"));
        op2.save(uselessNodeList, new File("uselessNodeList.dag"));
        op3.save(keywordSet, new File("keywordSet.dag"));
    }

    public int judgeInclusion(String P, String Q)
    {
        try
        {
            boolean m = queryList.get(P).keywords
                    .containsAll(queryList.get(Q).keywords);
            if (m)
                return -1;
            boolean n = queryList.get(Q).keywords
                    .containsAll(queryList.get(P).keywords);
            if (n)
                return 1;
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return 0;
    }

    public boolean minimizeInQList()
    {
        HashSet<String> set = InQList;
        boolean sys = false;
        try
        {
            String[] children = this.toArray(set);
            for (int i = 0; i < children.length; i++)
            {
                if (!set.contains(children[i]))
                    continue;
                for (int j = i + 1; j < children.length; j++)
                {
                    if (!set.contains(children[j]))
                        continue;
                    if (queryList.get(children[i]).keywords
                            .containsAll(queryList.get(children[j]).keywords))
                    {
                        set.remove(new String(children[j]));
                        sys = true;
                    }
                    else if (queryList.get(children[j]).keywords
                            .containsAll(queryList.get(children[i]).keywords))
                    {
                        set.remove(new String(children[i]));
                        sys = true;
                    }
                    else
                    {
                        HashSet<String> set1 = this.copy(query2parents
                                .get(children[i]));
                        HashSet<String> set2 = this.copy(query2parents
                                .get(children[j]));
                        set1.retainAll(set2);
                        if (!set1.isEmpty())
                        {
                            String[] parents = this.toArray(set1);
                            for (int k = 0; k < parents.length; k++)
                            {
                                if (queryList.get(query).keywords
                                        .containsAll(queryList.get(parents[k]).keywords))
                                {
                                    set.remove(new String(children[i]));
                                    set.remove(new String(children[j]));
                                    set.add(new String(parents[k]));
                                    sys = true;
                                }

                            }
                        }
                    }
                }
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return sys;
    }

    public HashSet<String> copy(HashSet<String> set)
    {
        HashSet<String> copySet = new HashSet<String>();
        try
        {
            Iterator<String> it = set.iterator();
            while (it.hasNext())
            {
                copySet.add(new String((String) it.next()));
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return copySet;
    }

    private String[] toArray(HashSet<String> hashSet)
    {
        String[] tmpArr = new String[hashSet.size()];
        int index = 0;
        for (Iterator<String> it = hashSet.iterator(); it.hasNext();)
        {
            tmpArr[index] = it.next();
            index++;
        }
        return tmpArr;
    }

    public static void display()
    {
        System.out.println("************keyword2query*************");
        Set<String> keyset1 = keyword2query.keySet();
        for (String key : keyset1)
        {
            System.out.print("\t" + key + ":");
            HashSet<String> values = keyword2query.get(key);
            for (String value : values)
            {
                System.out.print(value + "\t");
            }
            System.out.print("||");
        }
        System.out.println();

        System.out.println("************query2parents**************");
        Set<String> keyset2 = query2parents.keySet();
        for (String key : keyset2)
        {
            System.out.print("\t" + key + ":");
            HashSet<String> values = query2parents.get(key);
            for (String value : values)
            {
                System.out.print(value + "\t");
            }
            System.out.print("||");
        }
        System.out.println();

        System.out.println("************parents2query**************");
        // Set<String> keyset3 = parents2query.keySet();
        for (String key : keyset2)
        {
            System.out.print("\t" + key + ":");
            HashSet<String> values = parents2query.get(key);
            for (String value : values)
            {
                System.out.print(value + "\t");
            }
            System.out.print("||");
        }
        System.out.println();
    }

}
